﻿using System.Globalization;
using System;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.ApplicationServices;

namespace CadDotNetTools
{

    /// <summary>
    /// 表示动态属性的类型
    /// </summary>
    public enum DynamicBlockPropertyTypeCode
    {
        String = 1,  //字符串
        Real = 40,  //实数
        Short = 70,  // 短整型
        Long = 90,  //长整型
    }
    public static class BlockTools
    {
        /// <summary>
        /// 创建一个块并添加到数据库中
        /// </summary>
        /// <param name="db">图形数据库</param>
        /// <param name="blockName">块名</param>
        /// <param name="ents">实体列表</param>
        /// <returns>块表记录的Id</returns>
        public static ObjectId AddBlockTableRecord(this Database db, string blockName, List<Entity> ents)
        {
            //打开块表
            var bt = (BlockTable)db.BlockTableId.GetObject(OpenMode.ForRead);
            if (!bt.Has(blockName))  //判断是否存在名为blockName的块
            {
                //创建一个BlockTableRecord类的对象，表示索要创建的块
                var btr = new BlockTableRecord();
                //设置块名
                btr.Name = blockName;
                //将列表中的实体加入到新建的BlockTableRecord对象
                ents.ForEach(ent => btr.AppendEntity(ent));
                //切换块表为写的状态
                bt.UpgradeOpen();
                //在块表中加入blockName块
                bt.Add(btr);
                //通知事物处理
                db.TransactionManager.AddNewlyCreatedDBObject(btr, true);
                //为了安全，将块表状态改为读
                bt.DowngradeOpen();
            }

            //返回块表记录的Id
            return bt[blockName];
        }
        /// <summary>
        /// 重载AddBlockTableRecord扩展函数，使其能接受不固定的实体对象，这样在调用该函数时就不需要生成一个实体列表了 
        /// </summary>
        /// <param name="db"></param>
        /// <param name="blockName"></param>
        /// <param name="ents"></param>
        /// <returns></returns>
        public static ObjectId AddBlockTableRecord(this Database db, string blockName, params Entity[] ents)
        {
            return AddBlockTableRecord(db, blockName, ents.ToList());
        }
        /// <summary>
        /// 在Cad图形中插入参照块
        /// </summary>
        /// <param name="spaceId">表示块参照要加入的模型空间或图纸空间的Id</param>
        /// <param name="layer">块参照要加入的图层名</param>
        /// <param name="blockName">块参照所属的块名</param>
        /// <param name="position">插入点</param>
        /// <param name="scale">缩放比例</param>
        /// <param name="rotateAngle">旋转角度</param>
        /// <returns></returns>
        public static ObjectId InsertBlockReference(this ObjectId spaceId, string layer, string blockName, Point3d position, Scale3d scale, double rotateAngle = 0)
        {
            //存储要插入的块参照的Id
            ObjectId blockRefId;
            //获取数据库对象
            var db = spaceId.Database;
            //以读的方式打开块表
            var bt = (BlockTable)db.BlockTableId.GetObject(OpenMode.ForRead);
            //如果没有blockName表示的块，则程序返回
            if (!bt.Has(blockName)) return ObjectId.Null;
            //以写的方式打开空间（模型空间或图纸空间）
            var space = (BlockTableRecord)spaceId.GetObject(OpenMode.ForWrite);
            //创建一个块参照，并设置插入点
            var br = new BlockReference(position, bt[blockName]);
            //设置块参照的缩放比例
            br.ScaleFactors = scale;
            //设置块参照的层名
            br.Layer = layer;
            //设置块参照的旋转角度
            br.Rotation = rotateAngle;
            //在空间中加入创建的块参照
            blockRefId = space.AppendEntity(br);
            //通知事务处理加入创建的块参照
            db.TransactionManager.AddNewlyCreatedDBObject(br, true);
            //为了安全，将块表状态改为读
            space.DowngradeOpen();
            //返回添加的块参照的Id
            return blockRefId;
        }
        /// <summary>
        /// 块参照添加属性实体
        /// </summary>
        /// <param name="blockId">块表</param>
        /// <param name="atts">要加入的块属性列表</param>
        public static void AddAttributeToBlock(this ObjectId blockId, List<AttributeDefinition> atts)
        {
            //获取数据库对象
            var db = blockId.Database;
            //打开块表记录为写的状态
            var btr = (BlockTableRecord)blockId.GetObject(OpenMode.ForWrite);
            //遍历属性定义对象列表
            foreach (var att in atts)
            {
                //为块表记录添加属性
                btr.AppendEntity(att);
                //通知事务处理
                db.TransactionManager.AddNewlyCreatedDBObject(att, true);
            }
            //为了安全，将块表记录的状态改为读
            btr.DowngradeOpen();
        }
        /// <summary>
        /// 重载AddAttributeToBlock扩展函数，使其能接受不固定的属性定义对象
        /// </summary>
        /// <param name="blockId"></param>
        /// <param name="atts"></param>
        public static void AddAttributeToBlock(this ObjectId blockId, params AttributeDefinition[] atts)
        {
            blockId.AddAttributeToBlock(atts.ToList());
        }
        /// <summary>
        /// Cad图形中插入带属性的块参照
        /// </summary>
        /// <param name="spaceId">块参照要加入的模型空间或图纸空间的Id</param>
        /// <param name="layer">块参照要加入的图层名</param>
        /// <param name="blockName">块参照所属的块名</param>
        /// <param name="position">插入点</param>
        /// <param name="scale">缩放比例</param>
        /// <param name="rotateAngle">旋转角度</param>
        /// <param name="attNameValues">表示属性的名称与取值</param>
        /// <returns></returns>
        public static ObjectId InsertBlockReference(this ObjectId spaceId, string layer, string blockName, Point3d position, Scale3d scale, double rotateAngle, Dictionary<string, string> attNameValues)
        {
            //获取数据库对象
            var db = spaceId.Database;
            //以读的方式打开块表
            var bt = (BlockTable)db.BlockTableId.GetObject(OpenMode.ForWrite);
            //如果没有blockName表示的块，则程序返回
            if (!bt.Has(blockName)) return ObjectId.Null;
            //以写的方式打开空间（模型空间或图纸空间）
            var space = (BlockTableRecord)spaceId.GetObject(OpenMode.ForRead);
            //获取块表记录Id
            var btrId = bt[blockName];
            //打开块表记录
            var record = (BlockTableRecord)btrId.GetObject(OpenMode.ForRead);
            //创建一个块参照并设置插入点
            var br = new BlockReference(position, bt[blockName]);
            //设置块参照的缩放比例
            br.ScaleFactors = scale;
            //设置块参照的层名
            br.Layer = layer;
            //设置块参照的旋转角度
            br.Rotation = rotateAngle;
            //为了安全，将块表状态改为读
            space.AppendEntity(br);
            //判断块表记录是否包含属性定义
            if (record.HasAttributeDefinitions)
            {
                //若包含属性定义，则遍历属性定义
                foreach (var id in record)
                {
                    //检查是否是属性定义
                    var attDef = id.GetObject(OpenMode.ForRead) as AttributeDefinition;
                    if (attDef != null)
                    {
                        //创建一个新的属性对象
                        var attribute = new AttributeReference();
                        //从属性定义获得属性对象的对象特征
                        attribute.SetAttributeFromBlock(attDef, br.BlockTransform);
                        //设置属性对象的其他特征
                        attribute.Position = attDef.Position.TransformBy(br.BlockTransform);
                        attribute.Rotation = attDef.Rotation;
                        attribute.AdjustAlignment(db);
                        //判断是否包含指定的属性名称
                        if (attNameValues.ContainsKey(attDef.Tag.ToUpper()))
                        {
                            //设置属性值
                            attribute.TextString = attNameValues[attDef.Tag.ToUpper()].ToString();
                        }
                        //向块参照添加属性对象
                        br.AttributeCollection.AppendAttribute(attribute);
                        db.TransactionManager.AddNewlyCreatedDBObject(attribute, true);
                    }
                }
            }
            db.TransactionManager.AddNewlyCreatedDBObject(br, true);
            return br.ObjectId;  //返回添加的块参照的Id4
        }
        /// <summary>
        /// 更新块参照中的属性值
        /// </summary>
        /// <param name="blockRefId">块参照Id</param>
        /// <param name="attNameValue">需要更新的属性名称与取值</param>
        public static void UpdateAttributeInBlock(this ObjectId blockRefId, Dictionary<string, string> attNameValues)
        {
            //获取块参照对象
            var blockRef = blockRefId.GetObject(OpenMode.ForRead) as BlockReference;
            if (blockRef != null)
            {
                //遍历块参照中的属性
                foreach (ObjectId id in blockRef.AttributeCollection)
                {
                    //获取属性
                    var attref = id.GetObject(OpenMode.ForRead) as AttributeReference;
                    //判断是否包含指定的属性名称
                    if (attNameValues.ContainsKey(attref.Tag.ToUpper()))
                    {
                        //切换属性对象为写的状态
                        attref.UpgradeOpen();
                        //设置属性值
                        attref.TextString = attNameValues[attref.Tag.ToUpper()].ToString();
                    }
                    //为了安全，将属性对象的状态改为读
                    attref.DowngradeOpen();
                }
            }
        }
        /// <summary>
        /// 设置属性定义的通用样式
        /// </summary>
        /// <param name="att">属性</param>
        /// <param name="invisible">属性文字的可见性</param>
        public static void SetStyleForAtt(AttributeDefinition att, bool invisible)
        {
            //属性文字的高度
            att.Height = 0.15;
            //属性文字的水平对齐方式为居中
            att.HorizontalMode = TextHorizontalMode.TextCenter;
            //属性文字的垂直对齐方式为居中
            att.VerticalMode = TextVerticalMode.TextVerticalMid;
            //属性文字的可见性
            att.Invisible = invisible;
        }
        public static Dictionary<string, string> ReadDataInBlock(Database db, string blockName)
        {
            var dic = new Dictionary<string, string>();
            using (var trans = db.TransactionManager.StartTransaction())
            {
                var bt = trans.GetObject(db.BlockTableId, OpenMode.ForWrite) as BlockTable;
                foreach (var btrId in bt)
                {
                    var btr = trans.GetObject(btrId, OpenMode.ForWrite) as BlockTableRecord;
                    if (btr.Name == blockName)
                    {
                        if (!btr.HasAttributeDefinitions) return dic;
                        var collection = new ObjectIdCollection();
                        collection = btr.GetBlockReferenceIds(true, false);

                        foreach (ObjectId blrId in collection)
                        {
                            var blr = trans.GetObject(blrId, OpenMode.ForWrite) as BlockReference;
                            foreach (ObjectId attId in blr.AttributeCollection)
                            {
                                var att = trans.GetObject(attId, OpenMode.ForWrite) as AttributeReference;
                                dic.Add(att.Tag, att.TextString);
                            }
                        }
                    }
                }
                return dic;
            }
        }
        /// <summary>
        /// 获取动态块的动态属性值
        /// </summary>
        /// <param name="blockId">动态快的ObjectId</param>
        /// <param name="propName">需要查找的动态属性名</param>
        /// <returns>动态属性值</returns>
        public static string GetDynamicBlockValue(this ObjectId blockId, string propName)
        {
            //用于返回动态属性值的变量
            var propValue = "";
            //获得动态块的所有动态属性
            var props = blockId.GetDynProperties();
            //遍历动态属性
            foreach (DynamicBlockReferenceProperty prop in props)
            {
                Autodesk.AutoCAD.ApplicationServices.Application.ShowAlertDialog(prop.PropertyName);        /////////
                                                                                                            //如果动态属性的名称与输入的名称相同
                if (prop.PropertyName == propName)
                {
                    //获取动态属性值并结束遍历
                    propValue = prop.Value.ToString();
                    break;
                }
            }
            //返回动态属性值
            return propValue;
        }

        /// <summary>
        /// 获取动态块的动态属性值
        /// <这个未完成错误>
        /// </这个未完成错误>
        /// </summary>
        /// <param name="propName">需要查找的动态属性名</param>
        /// <returns>动态属性值</returns>
        public static string GetDynamicBlockValue(this Database db, string blockName, string propName)
        {
            //用于返回动态属性值的变量
            var propValue = "";
            //打开块表
            var bt = db.BlockTableId.GetObject(OpenMode.ForRead) as BlockTable;
            if (bt.Has(blockName))  //判断是否存在名为blockName的块
            {
                //获取当前空间
                var spaceId = db.CurrentSpaceId;
                //以写的方式打开空间
                var btr = (BlockTableRecord)spaceId.GetObject(OpenMode.ForWrite);
                if (btr.Name == blockName)  //找到名为blockName的块
                {
                    foreach (var id in btr)
                    {
                        //获得动态块的所有动态属性
                        var props = id.GetDynProperties();
                        //遍历动态属性
                        foreach (DynamicBlockReferenceProperty prop in props)
                        {
                            Autodesk.AutoCAD.ApplicationServices.Application.ShowAlertDialog(prop.PropertyName);
                            //如果动态属性的名称与输入的名称相同
                            if (prop.PropertyName == propName)
                            {
                                //获取动态属性值并结束遍历
                                propValue = prop.Value.ToString();
                                break;
                            }
                        }
                    }
                }
            }

            //返回动态属性值
            return propValue;
        }
        /// <summary>
        /// 获得动态块的所有动态属性
        /// </summary>
        /// <param name="blockId">动态块的ObjectId</param>
        /// <returns></returns>
        public static DynamicBlockReferencePropertyCollection GetDynProperties(this ObjectId blockId)
        {
            //获取块参照
            var br = blockId.GetObject(OpenMode.ForRead) as BlockReference;
            //如果不是动态块，则返回
            if (br == null && !br.IsDynamicBlock) return null;
            //返回动态块的动态属性
            return br.DynamicBlockReferencePropertyCollection;
        }
        /// <summary>
        /// 设置动态块的动态属性
        /// </summary>
        /// <param name="blockId">动态块的ObjectId</param>
        /// <param name="propName">动态属性的名称</param>
        /// <param name="value">动态属性的值</param>
        public static void SetDynamicBlockValue(this ObjectId blockId, string propName, object value)
        {
            //获得动态块的所有动态属性
            var props = blockId.GetDynProperties();
            //遍历动态属性
            foreach (DynamicBlockReferenceProperty prop in props)
            {
                //如果动态属性的名称与输入的名称相同且为可读
                if (prop.ReadOnly == false && prop.PropertyName == propName)
                {
                    //判断动态属性的类型并通过类型转化设置正确的动态属性值
                    switch (prop.PropertyTypeCode)
                    {
                        //短整型
                        case (short)DynamicBlockPropertyTypeCode.Short:
                            prop.Value = Convert.ToInt16(value);
                            break;
                        //长整型
                        case (short)DynamicBlockPropertyTypeCode.Long:
                            prop.Value = Convert.ToInt64(value);
                            break;
                        //实型
                        case (short)DynamicBlockPropertyTypeCode.Real:
                            prop.Value = Convert.ToDouble(value);
                            break;
                        default:  //   其他
                            prop.Value = value;
                            break;
                    }
                    break;
                }
            }
        }
        /// <summary>
        /// 获取特定类型的所有实体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="db"></param>
        /// <param name="mode"></param>
        /// <param name="OpenErased"></param>
        /// <returns>类型为T的实体列表</returns>
        public static List<T> GetEntsInDatabase<T>(this Database db, OpenMode mode, bool OpenErased)
            where T : Entity
        {
            var ed = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;
            //生命一个List类变量用于返回类型为T的实体列表
            var ents = new List<T>();
            //获取类型T代表DXF代码名用于构建选择集过滤器
            string dxfname = RXClass.GetClass(typeof(T)).DxfName;
            //构建选择集过滤器
            TypedValue[] values = { new TypedValue((int)DxfCode.Start, dxfname) };
            SelectionFilter filter = new SelectionFilter(values);
            //选择符合条件的所有实体
            PromptSelectionResult entSelected = ed.SelectAll(filter);
            if (entSelected.Status == PromptStatus.OK)
            {
                //循环遍历符合条件的实体
                foreach (var id in entSelected.Value.GetObjectIds())
                {
                    //将实体强制转化为T类型的对象 ， 不能将实体直接转化成泛型T，必须首先转换成object类
                    T t = (T)(object)id.GetObject(mode, OpenErased);
                    ents.Add(t);  //将实体添加到返回列表中
                }
            }
            return ents;  //返回类型为T的实体列表
        }
        /// <summary>
        /// 只需要以读的方式获取数据库中特定类型的实体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="db"></param>
        /// <returns></returns>
        public static List<T> GetEntsInDatabase<T>(this Database db)
            where T : Entity
        {
            return GetEntsInDatabase<T>(db, OpenMode.ForRead, false);
        }

        /// <summary>
        /// 获取特定类型(模型空间中)的所有实体,
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="db"></param>
        /// <param name="mode"></param>
        /// <param name="OpenErased"></param>
        /// <returns>类型为T的实体列表</returns>
        public static List<T> GetEntsInModelSpace<T>(this Database db, OpenMode mode, bool OpenErased)
            where T : Entity
        {
            var ed = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;
            //生命一个List类变量用于返回类型为T的实体列表
            var ents = new List<T>();
            //获取类型T代表DXF代码名用于构建选择集过滤器
            string dxfname = RXClass.GetClass(typeof(T)).DxfName;
            //构建选择集过滤器
            TypedValue[] values = { new TypedValue((int)DxfCode.Start, dxfname),
                new TypedValue((int) DxfCode.LayoutName,"Model") };
            SelectionFilter filter = new SelectionFilter(values);
            //选择符合条件的所有实体
            PromptSelectionResult entSelected = ed.SelectAll(filter);
            if (entSelected.Status == PromptStatus.OK)
            {
                //循环遍历符合条件的实体
                foreach (var id in entSelected.Value.GetObjectIds())
                {
                    //将实体强制转化为T类型的对象 ， 不能将实体直接转化成泛型T，必须首先转换成object类
                    T t = (T)(object)id.GetObject(mode, OpenErased);
                    ents.Add(t);  //将实体添加到返回列表中
                }
            }
            return ents;  //返回类型为T的实体列表
        }
        /// <summary>
        /// 获取特定类型(模型空间中)的所有实体,
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="db"></param>
        /// <param name="mode"></param>
        /// <param name="OpenErased"></param>
        /// <returns>类型为T的实体列表</returns>
        public static List<T> GetEntsInModelSpaces<T>(this Database db, OpenMode mode, bool OpenErased)
            where T : BlockReference
        {
            var ed = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;
            //生命一个List类变量用于返回类型为T的实体列表
            var ents = new List<T>();
            //获取类型T代表DXF代码名用于构建选择集过滤器
            string dxfname = RXClass.GetClass(typeof(T)).DxfName;
            //构建选择集过滤器
            TypedValue[] values = { new TypedValue((int)DxfCode.Start, dxfname),
                new TypedValue((int) DxfCode.LayoutName,"Model") };
            SelectionFilter filter = new SelectionFilter(values);
            //选择符合条件的所有实体
            PromptSelectionResult entSelected = ed.SelectAll(filter);
            if (entSelected.Status == PromptStatus.OK)
            {
                //循环遍历符合条件的实体
                foreach (var id in entSelected.Value.GetObjectIds())
                {
                    //将实体强制转化为T类型的对象 ， 不能将实体直接转化成泛型T，必须首先转换成object类
                    T t = (T)(object)id.GetObject(mode, OpenErased);
                    ents.Add(t);  //将实体添加到返回列表中
                }
            }
            return ents;  //返回类型为T的实体列表
        }
        /// <summary>
        /// 获取特定类型的所有实体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="db"></param>
        /// <param name="mode"></param>
        /// <param name="OpenErased"></param>
        /// <returns>类型为T的实体列表</returns>
        public static List<T> GetSelections<T>(this Database db, OpenMode mode, bool OpenErased)
            where T : Entity
        {
            var ed = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;
            //生命一个List类变量用于返回类型为T的实体列表
            var ents = new List<T>();
            //获取类型T代表DXF代码名用于构建选择集过滤器
            string dxfname = RXClass.GetClass(typeof(T)).DxfName;
            //构建选择集过滤器
            TypedValue[] values = { new TypedValue((int)DxfCode.Start, dxfname) };
            SelectionFilter filter = new SelectionFilter(values);
            //选择符合条件的所有实体
            PromptSelectionResult entSelected = ed.GetSelection(filter);
            if (entSelected.Status == PromptStatus.OK)
            {
                //循环遍历符合条件的实体
                foreach (var id in entSelected.Value.GetObjectIds())
                {
                    //将实体强制转化为T类型的对象 ， 不能将实体直接转化成泛型T，必须首先转换成object类
                    T t = (T)(object)id.GetObject(mode, OpenErased);
                    ents.Add(t);  //将实体添加到返回列表中
                }
            }
            return ents;  //返回类型为T的实体列表
        }
        /// <summary>
        /// 获取动态块/非动态块的块名
        /// </summary>
        /// <param name="bref"></param>
        /// <returns></returns>
        public static string GetBlockName(this BlockReference bref)
        {
            string blockName;  //存储块名
            if (bref == null) return null;  //如果块参照不存在，则返回
            if (bref.IsDynamicBlock)  //如果是动态块
            {
                ObjectId idDyn = bref.DynamicBlockTableRecord;  //获取动态块所属的动态块表记录
                                                                //打开动态块表记录
                BlockTableRecord btr = (BlockTableRecord)idDyn.GetObject(OpenMode.ForRead);
                blockName = btr.Name; //获取块名
            }
            else  //非动态块
            {
                blockName = bref.Name;  //获取块名
            }
            return blockName;  //返回块名
        }

        /// <summary>
        /// 动态块的读取(Dwg)
        /// </summary>
        /// <param name="blockDWGName">dwg文件名</param>
        /// <param name="blockName">动态块名</param>
        public static void InitialZwBlockReference(this string blockDWGName, string blockName)
        {
            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = doc.Database;
            string fileName = $"{blockDWGName}.dwg";
            ObjectIdCollection oids = new ObjectIdCollection();
            ObjectIdCollection newoids = new ObjectIdCollection();
            IdMapping idMap = new IdMapping();
            //将动态块拷贝到当前document，生成块定义
            using (Database db2 = new Database(false, false))
            {
                db2.ReadDwgFile(fileName, System.IO.FileShare.Read, true, null);
                db2.CloseInput(true);
                using (Transaction tr = db2.TransactionManager.StartTransaction())
                {
                    BlockTable blockTbl = tr.GetObject(db2.BlockTableId, OpenMode.ForRead) as BlockTable;
                    BlockTableRecord modelSpace1 = tr.GetObject(blockTbl[BlockTableRecord.ModelSpace], OpenMode.ForRead) as BlockTableRecord;
                    foreach (ObjectId oid in modelSpace1)
                    {
                        oids.Add(oid);
                    }
                }
                db2.WblockCloneObjects(oids, db.CurrentSpaceId, idMap, DuplicateRecordCloning.Ignore, false);
                foreach (ObjectId oid in oids)
                {
                    try
                    {
                        if (!newoids.Contains(idMap[oid].Value))
                        {
                            newoids.Add(idMap[oid].Value);
                        }
                    }
                    catch { }

                }
            }
            //设置显示的值
            using (DocumentLock dl = doc.LockDocument())
            {
                using (Transaction trans = doc.TransactionManager.StartTransaction())
                {
                    Entity ent = trans.GetObject(newoids[0], OpenMode.ForWrite) as Entity;
                    if (ent is BlockReference)
                    {
                        CheckBlockPropertyValue((BlockReference)ent, blockName);
                    }
                    //trans.Commit();
                }
            }
        }
        /// <summary>
        /// 根据想要显示的值去显示
        /// </summary>
        /// <param name="br"></param>
        /// <param name="blockName"></param>
        public static void CheckBlockPropertyValue(BlockReference br, string blockName)
        {
            DynamicBlockReferencePropertyCollection properties = br.DynamicBlockReferencePropertyCollection;
            for (int i = 0; i < properties.Count; i++)
            {
                DynamicBlockReferenceProperty property = properties[i];
                foreach (object item in property.GetAllowedValues())
                {
                    if (item.ToString() == blockName)
                    {
                        property.Value = item;
                        break;
                    }
                }
            }
        }
        /// <summary>
        /// 修改动态块属性
        /// </summary>
        /// <param name="blockName">动态块名</param>
        /// <param name="paramName">修改的属性名</param>
        /// <param name="paramValue">修改的属性值</param>
        /// <param name="trans">事物</param>
        public static void ModifyDynamicBlockParameter(this string blockName, string paramName, object paramValue, Transaction trans)
        {
            var doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            var db = doc.Database;

            //获取当前块的所有引用块
            ObjectIdCollection ids = new ObjectIdCollection();

            ObjectId btrId = db.CurrentSpaceId.GetObject(OpenMode.ForWrite).ObjectId;

            BlockTableRecord btr = trans.GetObject(btrId, OpenMode.ForWrite) as BlockTableRecord;
            //var btr = trans.GetObject(db.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;

            foreach (ObjectId entId in btr)
            {
                var ent = trans.GetObject(entId, OpenMode.ForRead) as BlockReference;
                if (ent is BlockReference && ent.Name == blockName)
                {
                    //BlockReference br = ent as BlockReference;
                    ids.Add(ent.ObjectId);
                }
            }


            //修改自定义参数的值
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                foreach (ObjectId id in ids)
                {
                    //获取块引用对象
                    BlockReference br = tr.GetObject(id, OpenMode.ForWrite) as BlockReference;
                    DynamicBlockReferencePropertyCollection props = br.DynamicBlockReferencePropertyCollection;

                    foreach (DynamicBlockReferenceProperty prop in props)
                    {
                        if (string.Equals(prop.PropertyName, paramName, StringComparison.CurrentCultureIgnoreCase))
                        {
                            //获取参数并修改值
                            var parameter = prop;
                            //if (parameter != null)
                            //{
                            prop.Value = paramValue;
                            break;
                            // }
                        }
                    }
                }

                tr.Commit();
            }
        }

        /// <summary>
        /// 从外部文件导入快
        /// </summary>
        /// <param name="destDb">目标数据库</param>
        /// <param name="sourceFileName">包含完整路径的外部文件名</param>
        public static void ImportBlocksFromDwg(this Database destDb, string sourceFileName)
        {
            //创建一个新的数据库对象，作为源数据库，以读入外部文件的对象
            var sourceDb = new Database();
            try
            {
                //把DWG文件读入到一个临时的数据库中
                sourceDb.ReadDwgFile(sourceFileName, System.IO.FileShare.Read, true, null);
                //创建一个变量用来存储块的ObjectId列表
                var blockIds = new ObjectIdCollection();
                //获取源数据库的事物处理管理器
                Autodesk.AutoCAD.DatabaseServices.TransactionManager tm = sourceDb.TransactionManager;
                //在源数据库中开始事务处理
                using (var myT = tm.StartTransaction())
                {
                    //打开源数据库中的块表
                    var bt = tm.GetObject(sourceDb.BlockTableId, Autodesk.AutoCAD.DatabaseServices.OpenMode.ForRead, false) as BlockTable;
                    //遍历每个块
                    foreach (var btrId in bt)
                    {
                        var btr = tm.GetObject(btrId, Autodesk.AutoCAD.DatabaseServices.OpenMode.ForRead, false) as BlockTableRecord;
                        //只加入命名块和非布局块到复制列表中
                        if (!btr.IsAnonymous && !btr.IsLayout)
                        {
                            blockIds.Add(btrId);
                        }
                        btr.Dispose();
                    }
                    bt.Dispose();
                }
                //定义一个IdMapping 对象
                IdMapping mapping = new IdMapping();
                //从源数据库向目标数据库复制块表记录
                sourceDb.WblockCloneObjects(blockIds, destDb.BlockTableId, mapping, DuplicateRecordCloning.Replace, false);

            }
            catch (System.Exception ex)
            {

                Autodesk.AutoCAD.ApplicationServices.Application.ShowAlertDialog("复制错误：" + ex.Message);
            }
            sourceDb.Dispose();  //操作完成，销毁源数据库
        }

        /// <summary>
        /// 找到自定义属性的类型
        /// </summary>
        /// <param name="doc">Document</param>
        /// <param name="blockName">块名</param>
        public static void GetPropType(this Document doc, string blockName)
        {
            try
            {
                var db = doc.Database;
                var ed = doc.Editor;
                using (var trans = db.TransactionManager.StartTransaction())
                {

                    ObjectId btrId = doc.Database.CurrentSpaceId.GetObject(OpenMode.ForWrite).ObjectId;

                    //BlockTableRecord btr = trans.GetObject(btrId, OpenMode.ForWrite) as BlockTableRecord;
                    var btr = trans.GetObject(doc.Database.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;
                    //获取当前块的所有引用块
                    ObjectIdCollection ids = new ObjectIdCollection();
                    foreach (ObjectId entId in btr)
                    {
                        BlockReference ent = trans.GetObject(entId, OpenMode.ForRead) as BlockReference;
                        ed.WriteMessage($"\n 块名：{ent.Name}");
                        ed.WriteMessage($"\n实际块名：{ent.BlockName.FirstOrDefault()}");

                        if (ent is BlockReference && ent.Name == blockName)         //AE_TOTAL_FRONT
                        {
                            //BlockReference br = ent as BlockReference;
                            ids.Add(ent.ObjectId);
                            ed.WriteMessage($"\n 找到了 ！！！{ent.Name}");
                        }
                    }
                    using (Transaction tr = db.TransactionManager.StartTransaction())
                    {
                        foreach (ObjectId id in ids)
                        {
                            //获取块引用对象
                            BlockReference br = tr.GetObject(id, Autodesk.AutoCAD.DatabaseServices.OpenMode.ForWrite) as BlockReference;
                            DynamicBlockReferencePropertyCollection props = br.DynamicBlockReferencePropertyCollection;

                            foreach (DynamicBlockReferenceProperty prop in props)
                            {
                                if (string.Equals(prop.PropertyName, "铰链锁具可见性", StringComparison.CurrentCultureIgnoreCase))
                                {
                                    //获取参数并修改值
                                    var parameter = prop;
                                    //if (parameter != null)
                                    //{
                                    ed.WriteMessage($"\n 参数s是：{prop.Value}!!!");
                                    ed.WriteMessage($"\n 参数s是Type：{(prop.Value).GetType()}!!!");
                                    break;
                                    // }
                                }
                            }
                            trans.Commit();
                        }
                        trans.Commit();

                    }

                }
            }
            catch (System.Exception ex)
            {

                Autodesk.AutoCAD.ApplicationServices.Application.ShowAlertDialog(ex.Message);
            }
        }
    }
}
